`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2024/11/12 13:50:23
// Design Name: 
// Module Name: CRC_Process
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module CRC_Process#(
    parameter           P_CRC_ON      = 1       
)(
    input               i_clk                   ,
    input               i_rst                   ,

    input  [7 :0]       i_axis_rx_data          ,
    input  [31:0]       i_axis_rx_user          ,//[31:16]-type；[15:0]-len；
    input               i_axis_rx_last          ,
    input               i_axis_rx_valid         ,
    output              o_axis_rx_ready         ,
    input  [31:0]       i_crc_result            ,
    input               i_crc_valid             ,

    output [7 :0]       o_axis_crx_data         ,
    output [31:0]       o_axis_crx_user         ,
    output              o_axis_crx_last         ,
    output              o_axis_crx_valid        
);


reg  [7 :0]             ri_axis_rx_data         ;
reg  [7 :0]             ri_axis_rx_data_1d      ;
reg  [7 :0]             ri_axis_rx_data_2d      ;
reg  [7 :0]             ri_axis_rx_data_3d      ;
reg  [31:0]             ri_axis_rx_user         ;
reg                     ri_axis_rx_last         ;
reg                     ri_axis_rx_valid        ;
reg                     ri_axis_rx_valid_1d     ;
reg  [31:0]             ri_crc_result           ;
reg                     ri_crc_valid            ;
reg  [7 :0]             ro_axis_crx_data        ;
reg  [31:0]             ro_axis_crx_user        ;
reg                     ro_axis_crx_last        ;
reg                     ro_axis_crx_valid       ;
reg  [10:0]             r_bram_waddr            ;
reg  [10:0]             r_bram_InitAddr         ;
reg  [10:0]             r_bram_raddr            ;
reg                     r_bram_ren              ;
reg                     r_bram_ren_1d           ;
reg  [31:0]             r_crc_result            ;
reg                     r_crc_check             ;
reg                     r_crc_valid             ;
reg  [15:0]             r_len                   ;
reg                     r_fifo_rden             ;
reg                     r_fifo_rden_1d          ;
reg                     r_OutRun                ;
reg  [15:0]             r_OutCnt                ;

wire [7 :0]             w_bram_dout             ;
wire                    w_fifo_wren             ;
wire [47:0]             w_fifo_dout             ;
wire                    w_fifo_full             ;
wire                    w_fifo_empty            ;

assign w_fifo_wren      = r_crc_valid & r_crc_check;
assign o_axis_rx_ready  = 1                     ;
assign o_axis_crx_data  = ro_axis_crx_data      ;
assign o_axis_crx_user  = ro_axis_crx_user      ;
assign o_axis_crx_last  = ro_axis_crx_last      ;
assign o_axis_crx_valid = ro_axis_crx_valid     ;

BRAM_SD_8X2048 BRAM_SD_8X2048_u0 (
  .clka                 (i_clk              ),
  .ena                  (ri_axis_rx_valid   ),
  .wea                  (ri_axis_rx_valid   ),
  .addra                (r_bram_waddr       ),
  .dina                 (ri_axis_rx_data    ),
  .clkb                 (i_clk              ),
  .enb                  (r_bram_ren         ),
  .addrb                (r_bram_raddr       ),
  .doutb                (w_bram_dout        ) 
);

FIFO_48X32 FIFO_48X32_u0 (
  .clk                  (i_clk                          ),      // input wire clk
  .din                  ({ri_axis_rx_user[31:16],(r_len - 16'd4),{5'd0,r_bram_InitAddr}} ),      // input wire [31 : 0] din
  .wr_en                (w_fifo_wren                    ),  // input wire wr_en
  .rd_en                (r_fifo_rden                    ),  // input wire rd_en
  .dout                 (w_fifo_dout                    ),    // output wire [31 : 0] dout
  .full                 (w_fifo_full                    ),    // output wire full
  .empty                (w_fifo_empty                   )  // output wire empty
);
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ri_axis_rx_data     <= 'd0;
        ri_axis_rx_user     <= 'd0;
        ri_axis_rx_last     <= 'd0;
        ri_axis_rx_valid    <= 'd0;
        ri_crc_result       <= 'd0;
        ri_crc_valid        <= 'd0;
        ri_axis_rx_data_1d  <= 'd0;
        ri_axis_rx_data_2d  <= 'd0;
        ri_axis_rx_data_3d  <= 'd0;
        ri_axis_rx_valid_1d <= 'd0;
        r_fifo_rden_1d      <= 'd0;
        r_bram_ren_1d       <= 'd0;
    end else begin  
        ri_axis_rx_data     <= i_axis_rx_data       ;
        ri_axis_rx_user     <= i_axis_rx_user       ;
        ri_axis_rx_last     <= i_axis_rx_last       ;
        ri_axis_rx_valid    <= i_axis_rx_valid      ;
        ri_crc_result       <= i_crc_result         ;
        ri_crc_valid        <= i_crc_valid          ;
        ri_axis_rx_data_1d  <= ri_axis_rx_data      ;
        ri_axis_rx_data_2d  <= ri_axis_rx_data_1d   ;
        ri_axis_rx_data_3d  <= ri_axis_rx_data_2d   ;
        ri_axis_rx_valid_1d <= ri_axis_rx_valid     ;
        r_fifo_rden_1d      <= r_fifo_rden          ;
        r_bram_ren_1d       <= r_bram_ren           ;
    end 
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_len <= 'd0;
    else if(!r_crc_check & r_crc_valid)
        r_len <= 'd0;
    else if(w_fifo_wren)
        r_len <= 'd0;
    else if(ri_axis_rx_valid)
        r_len <= r_len + 1;
    else 
        r_len <= r_len;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_bram_InitAddr <= 'd0;
    else if(ri_axis_rx_valid & !ri_axis_rx_valid_1d)
        r_bram_InitAddr <= r_bram_waddr;
    else 
        r_bram_InitAddr <= r_bram_InitAddr;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_bram_waddr <= 'd0;
    else if(r_crc_valid & !r_crc_check)
        r_bram_waddr <= r_bram_InitAddr;
    else if(r_crc_valid &  r_crc_check)
        case(r_bram_waddr)
            0       :r_bram_waddr <= 2044;
            1       :r_bram_waddr <= 2045;
            2       :r_bram_waddr <= 2046;
            3       :r_bram_waddr <= 2047;
            default :r_bram_waddr <= r_bram_waddr - 4;
        endcase
    else if(ri_axis_rx_valid && r_bram_waddr == 2048 - 1)
        r_bram_waddr <= 'd0;
    else if(ri_axis_rx_valid)
        r_bram_waddr <= r_bram_waddr + 'd1;
    else 
        r_bram_waddr <= r_bram_waddr;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_crc_result <= 'd0;
    else if(ri_axis_rx_last)
        r_crc_result <= {ri_axis_rx_data,ri_axis_rx_data_1d,ri_axis_rx_data_2d,ri_axis_rx_data_3d};
    else 
        r_crc_result <= r_crc_result;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)   
        r_crc_valid <= 'd0;
    else 
        r_crc_valid <= ri_crc_valid;
end     

/*----CRC Error ----*/
// always@(posedge i_clk,posedge i_rst)
// begin
//     if(i_rst)       
//         r_crc_check <= 'd0;
//     else if(ri_axis_rx_last)
//         r_crc_check <= ~r_crc_check;
//     else 
//         r_crc_check <= r_crc_check;
// end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)       
        r_crc_check <= 'd0;
    else if(!P_CRC_ON)
        r_crc_check <= 'd1;
    else if(ri_crc_valid && ri_crc_result != r_crc_result)
        r_crc_check <= 'd0;
    else if(ri_crc_valid && ri_crc_result == r_crc_result)
        r_crc_check <= 'd1;
    else 
        r_crc_check <= r_crc_check;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)  
        r_fifo_rden <= 'd0;
    else if(!w_fifo_empty && !r_fifo_rden && !r_OutRun)
        r_fifo_rden <= 'd1;
    else    
        r_fifo_rden <= 'd0;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)  
        r_OutRun <= 'd0;
    else if(r_bram_ren && r_OutCnt == w_fifo_dout[31:16] - 1)
        r_OutRun <= 'd0;
    else if(!w_fifo_empty && !r_fifo_rden && !r_OutRun)
        r_OutRun <= 'd1;
    else 
        r_OutRun <= r_OutRun;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)  
        r_OutCnt <= 'd0;
    else if(r_bram_ren && r_OutCnt == w_fifo_dout[31:16] - 1)
        r_OutCnt <= 'd0;
    else if(r_bram_ren)
        r_OutCnt <= r_OutCnt + 'd1;
    else 
        r_OutCnt <= r_OutCnt;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)  
        r_bram_ren <= 'd0;
    else if(r_bram_ren && r_OutCnt == w_fifo_dout[31:16] - 1)
        r_bram_ren <= 'd0;
    else if(r_fifo_rden_1d)
        r_bram_ren <= 'd1;
    else        
        r_bram_ren <= r_bram_ren;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)  
        r_bram_raddr <= 'd0;
    else if(r_bram_ren)
        r_bram_raddr <= r_bram_raddr + 1;
    else if(r_fifo_rden_1d)
        r_bram_raddr <= w_fifo_dout[10:0];
    else 
        r_bram_raddr <= r_bram_raddr;
end
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)  begin
        ro_axis_crx_data  <= 'd0;
        ro_axis_crx_user  <= 'd0;
        ro_axis_crx_valid <= 'd0;
    end else begin
        ro_axis_crx_data  <= w_bram_dout;
        ro_axis_crx_user  <= {w_fifo_dout[47:32],w_fifo_dout[31:16]};
        ro_axis_crx_valid <= r_bram_ren_1d;
    end
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) 
        ro_axis_crx_last <= 'd0;
    else if(!r_bram_ren && r_bram_ren_1d)
        ro_axis_crx_last <= 'd1;
    else 
        ro_axis_crx_last <= 'd0;
end


endmodule
